/*----------------------------------------------------------------------------

	Copyright (c) 2006, Creator of the Cant Project.
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

	+ Redistributions of source code must retain the above copyright notice,
	this list of conditions and the following disclaimer.

	+ Redistributions in binary form must reproduce the above copyright notice,
	this list of conditions and the following disclaimer in the documentation
	and/or other materials provided with the distribution.

	+ Neither the name of the Creator of the Cant Project nor the names of its
	contributors may be used to endorse or promote products derived from this
	software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.

----------------------------------------------------------------------------*/

#ifndef	_PROJECT_HPP_
#define	_PROJECT_HPP_

#include	<fstream>
#include	<iostream>
#include	<map>
#include	<sstream>
#include	<string>

#include	"except.hpp"
#include	"projlist.hpp"
#include	"projtag.hpp"
#include	"types.hpp"
#include	"../util/log.hpp"
#include	"../util/util.hpp"
#include	"tiny/tinyxml.h"



class ProjectList;



/**
	Encapsulates an <i>XML</i> project file.
	
	
	@version	0.1
	@author		<a href="mailto:cant.project@gmail.com">Mikey</a>
*/
class Project
{
	private:
		/**
			Constant.
			
		*/
		static const std::string		STR_TAG_PROJECT;
		static const std::string		STR_TAG_INCLUDE;
		static const std::string		STR_TAG_PROPERTY;
		static const std::string		STR_TAG_TARGET;
		
		static const std::string		STR_ATTRIB_BASEDIR;
		static const std::string		STR_ATTRIB_DEFAULT;
		static const std::string		STR_ATTRIB_DESCRIPTION;
		static const std::string		STR_ATTRIB_NAME;
		static const std::string		STR_ATTRIB_INCLUDE_PATH;
		
		static const std::string		STR_PROPERTY_START;
		static const std::string		STR_PROPERTY_END;
		
		static const std::string		STR_EMPTY;

		
		/**
			Separator for namespace/name pair.
			
		*/
		static const char				CHAR_SEPARATOR_PAIR		= ':';
		
		
		/**
			Base-directory attribute.
			
		*/
		std::string					m_strBaseDirectory;
		
		
		/**
			Default target attribute.
			
		*/
		std::string					m_strDefaultTarget;
		
		
		/**
			Description attribute.
			
		*/
		std::string					m_strDescription;
		
		
		/**
			Name attribute.
			
		*/
		std::string					m_strName;
		
		
		/**
			Map of properties.
			
		*/
		typePropertyMap				m_mapProperties;
		
		
		/**
			Map of targets.
			
		*/
		typeTargetMap				m_mapTargets;
		
		
		/**
			Shared list of loaded projects.
			
		*/
		static ProjectList			m_listProjects;

	
	private:
		/**
			Constructor.
			
			@param		a_strFilePath		path of file to be parsed.
		*/
		//!Project(std::string a_strFilePath );
		
		
		/**
			Default constructor.
			
		*/
		Project(void );
		
		
		/**
			Parses the contents of an <i>XML</i> file.
			
			@param		a_elemRoot		root element of project.
			@return		value of <code>isCreated</code>.
		*/
		void	parse(TiXmlElement* a_elemRoot ) throw(ParserException );
		
		
		/**
			Splits a given name into a namespace/name pair.
			
			The expected form is <code>namespace:name</code>. If the separator
			(<code>:</code>) is not found, the namespace is assumed to be the
			current one.
			
			@param		a_strName		name to be split.
			@param		a_tuple			tuple that will contain the name and
										namespace.
		*/
		void	splitName(const std::string& a_strName, StringTuple& a_tuple );
	
	
	public:
		/**
			Destructor.
			
		*/
		virtual	~Project() throw();
		
		
		/**
			Gives a named property.
			
			@param		a_strName			name of property.
		*/
		std::string	getProperty(const std::string& a_strName );
		
		
		/**
			Gives a map of all properties.
			
		*/
		typePropertyMap&	getProperties(void );
				
		
		/**
			Gives a named target.
			
			If the target doesn't exist, a <code>TagException</code> is
			thrown.
			
			@param		a_strName			name of target.
		*/
		ProjectTarget	getTarget(const std::string& a_strName );
		
		
		/**
			Gives a map of all targets.
			
		*/
		typeTargetMap&	getTargets(void );
		
		
		/**
			Indexer to give a named target.
			
		*/
		ProjectTarget	operator[](const std::string& );
		
		
		/**
			Evaluates a string, expanding all properties.
			
			@param		a_strUnexpanded		unexpanded string.
			@return		expanded string.
		*/
		std::string	evaluate(const std::string& a_strUnexpanded );
		
		
		/**
			Gives the base-directory.
			
			@see		m_strBaseDirectory.
			
			@return		base-directory.
		*/
		std::string	getBaseDirectory(void ) const;
		
		
		/**
			Gives the default target.
			
			@see		m_strDefaultTarget
			
			@return		default target.
		*/
		std::string	getDefaultTarget(void ) const;
		
		
		/**
			Gives the description.
			
			@see		m_strDescription
			
			@return		description.
		*/
		std::string	getDescription(void ) const;
		
		
		/**
			Gives the name.
			
			@see		m_strName
			
			@return		name.
		*/
		std::string	getName(void ) const;
	
	
	public:
		/**
			Instantiator for <code>Project</code> objects.
			
			@param		a_strFilePath		path of build file.
			@return		pointer to created <code>Project</code> object.
		*/
		static Project*	createProject(const std::string& a_strFilePath );
		
		
		/**
			Gives a list of all loaded <code>Project</code> objects.
			
			@return		list of all loaded <code>Project</code> objects.
		*/
		static ProjectList&	getProjectList(void );
};

#endif
